%% Train new neural network
% Data ...          Trainingsdaten
% Target ...        Klassenlabels der Trainingsdaten
% ArchLayer ...     Architektur des Netwerks
% ArchFunc ...      Aktivierungsfunktion(en) der verborgenen Schichten
%   sowie der Ausgabeschicht z.B.: {'purelin' 'tansig'}
% LearnRate ...     Lernrate des Netzwerks
% Momentum ...      Momentum um ueber etwaige Plateaus hinweg zu kommen.

function network = neural_train (Data, Target, ArchLayer, ArchFunc, LearnRate, Momentum) 

%% Variablen initialisieren
X = Data; % Eingabedaten
Tn = Target; % Klassenlabels zu den Eingabedaten
Si = ArchLayer; % Architektur des Netwerks
% Bsp: Si = [20]; % Architektur des Netzwerks: Eine verborgene
% Schicht mit 20 Knoten
Lr = LearnRate; % Lernrate
Mom = Momentum; % Momentum
TFi = ArchFunc;
% Bsp: TFi = {'purelin' 'tansig'}; Erklaerung der Funktionen siehe
% Initialisierung des Netzwerks (unten)

%% Initialiserung des Netzwerks
%   * 'transig' gibt an, dass fuer die verborgene Schicht die hyperbolische
%       tangent sigmoid Aktivierungsfunktion verwendet werden soll
%   * 'purelin' gibt an, dass fuer die Ausgabeschicht eine lineare
%       Aktivierungsfunktion verwendet werden soll
%   * 'traingdm' gibt an, dass als Trainingsfunktion ein
%       Gradientenabstiegsverfahren mit Momentum gewaehlt wird, welches die
%       Gewichte so veraendert, dass sich der Fehler auf ein lokales
%       Minimum zubewegt. Gleichzeitig wird auch ein Momentum verwendet, um
%       ueber Plateaus von gleicher Fehlerrate bei ungleichen gewichten hinaus
%       kommen zu koennen.
%   * 'learngdm' gibt an, dass als Lernfunktion
%   * 'mse' gibt an, das als performance Funktion der Mittelwert der
%       quadratischen Fehler (mean squared normalized error) herangezogen werden soll
net = newpr(X, Tn, Si, TFi);%, 'traingdm', 'learngdm', 'mse');

% Restliche Parameter setzen
%net.trainParam.epochs = 200; % Anzahl der Epochen
net.trainParam.lr = Lr;    % Lernrate
net.trainParam.mc = Mom;    % Momentum
%net.trainParam.goal = 0.05; % Zielfehlerrate, wenn diese erreicht ist, wird abgebrochen

%% Pre- und Postprocessing Funktionen festlegen
% Als erstes werden die Eingabevektoren bezueglich Mittelwert (=Null) und
% Varianz mittels "mapstd(.)" normalisiert. 
% Danach wird die Principal Component Analysis durchgefuehrt und dabei
% werden jene Components weggeworfen, die weniger als 2% zu der
% globalen Variation der Daten beitragen. processpca(pn, 0.02);
net.inputs{1}.processFcns = {'mapstd', 'processpca'};
net.inputs{1}.processParams{2}.maxfrac = 0.02;
% Am schluss muss die Ruecktransformation des Mittelwertes und der
% Variation erfolgen
net.outputs{2}.processFcns = {'mapstd'};

% Ausgabe von Informationen in der Kommandozeile aktivieren
net.trainParam.showCommandLine = false; % Ausgabe in Commandozeile aktivieren
net.trainParam.show = 5; % Alle 5 Epochen eine Ausgabe in der Commandozeile

% Start des Trainings
net = train (net, X, Tn);
    
network = net;

end %function